<?php

namespace App\Service\GuildManage;

use App\Cache\RedisKey;
use App\Constants\ErrorCode;
use App\Constants\GuildCode;
use App\Exception\ApiException;
use App\Helpers\RedisUtil;
use App\Model\GuildManage\GuildAccount;
use App\Model\GuildManage\GuildBalance;
use App\Model\GuildManage\GuildWithdrawal;
use App\Service\BaseService;
use App\Service\ServiceTrait\GetUserInfoTrait;
use App\Service\ServiceTrait\GuildTrait;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use RedisException;
class ApplyService extends BaseService
{
    use \Hyperf\Di\Aop\ProxyTrait;
    use \Hyperf\Di\Aop\PropertyHandlerTrait;
    function __construct(\Hyperf\AsyncQueue\Driver\DriverFactory $driverFactory)
    {
        if (method_exists(parent::class, '__construct')) {
            parent::__construct(...func_get_args());
        }
        $this->__handlePropertyHandler(__CLASS__);
    }
    use GetUserInfoTrait, GuildTrait;
    /**
     * @Inject
     * @var GuildWithdrawal
     */
    private $guildWithdrawalModel;
    /**
     * @Inject
     * @var GuildBalance
     */
    private $guildBalanceModel;
    /**
     * 动作执行者(提现的人)
     * @var mixed
     */
    private $actionUserId;
    /**
     * 余额账户
     * @var
     */
    private $balanceInfo;
    /**
     * 操作的金额
     * @var
     */
    private $handleRmb;
    /**
     * 主控制器
     * @return string[]
     * @throws RedisException
     */
    public function handle() : array
    {
        $this->actionUserId = $this->getUserId();
        if (empty($this->actionUserId)) {
            throw new ApiException('登录失效，请重新登录');
        }
        $lockKey = RedisKey::operationApplyLock($this->actionUserId);
        if (!RedisUtil::addLock($lockKey, 10)) {
            throw new ApiException('操作的太快了，请稍后再操作哦！');
        }
        if (!$this->checkGuildStatus($this->actionUserId)) {
            throw new ApiException('亲,暂时没有此操作权限哦!', ErrorCode::DEFAULT_ERROR);
        }
        $accountId = $this->request->input('account_id');
        $this->handleRmb = $this->request->input('withdraw_rmb');
        $withdrawType = $this->request->input('withdraw_account_type');
        $accountInfo = $this->checkAccount($accountId, $this->actionUserId);
        if ($this->handleRmb < GuildCode::MINIMUM_WITHDRAWAL) {
            throw new ApiException('单次提现最小值仅支持' . GuildCode::MINIMUM_WITHDRAWAL . '元');
        }
        if ($this->handleRmb > GuildCode::MAXIMUM_WITHDRAWAL) {
            throw new ApiException('单次提现最大值仅支持' . GuildCode::MAXIMUM_WITHDRAWAL . '元');
        }
        $this->checkTodayCount();
        $this->checkAccountBalance();
        $serviceCharge = $withdrawType == 1 ? GuildCode::DAY_SERVICE_CHARGE : GuildCode::ROUTINE_SERVICE_CHARGE;
        //实际到账金额 精度计算
        $realityRmb = bcsub($this->handleRmb, bcmul($this->handleRmb, $serviceCharge, 2), 2);
        $defaultAccountInfo = null;
        if ($accountInfo->default == 0) {
            $defaultAccountInfo = (new GuildAccount())->getDefaultAccountByUserId($this->actionUserId);
        }
        //事务操作数据库
        Db::beginTransaction();
        try {
            //扣除账户金额
            $this->balanceInfo->have_access_balance = $this->balanceInfo->have_access_balance - $this->handleRmb;
            if (!$this->balanceInfo->save()) {
                Db::rollBack();
                throw new ApiException('余额扣除失败');
            }
            //修改默认账号
            $this->changeDefaultAccount($accountInfo, $defaultAccountInfo);
            //添加一个提现订单
            $insertModel = new GuildWithdrawal();
            $insertModel->user_id = $this->actionUserId;
            $insertModel->withdraw_rmb = $this->handleRmb;
            $insertModel->reality_rmb = $realityRmb;
            $insertModel->service_charge = $serviceCharge;
            $insertModel->withdraw_account_id = $accountInfo->id;
            $insertModel->withdraw_account = $accountInfo->account;
            $insertModel->withdraw_real_name = $accountInfo->real_name;
            $insertModel->withdraw_id_card = $accountInfo->id_card;
            $insertModel->withdraw_type = $accountInfo->type;
            $insertModel->withdraw_account_type = $withdrawType;
            $insertModel->status = GuildWithdrawal::STATUS_ING;
            if (!$insertModel->save()) {
                Db::rollBack();
                throw new ApiException('提现记录增加失败');
            }
            Db::commit();
        } catch (\Throwable $ex) {
            Db::rollBack();
            throw new ApiException($ex->getMessage());
        }
        RedisUtil::delLock($lockKey);
        return ['msg' => '申请成功，请耐心等待到账'];
    }
    /**
     * 修改默认账号
     * @param $accountInfo
     * @param $defaultAccountInfo
     * @return void
     */
    private function changeDefaultAccount($accountInfo, $defaultAccountInfo)
    {
        //如果本身用来结算的账号已经是 默认值 那么不发生改变直接回去
        if ($accountInfo->default == 1) {
            return;
        }
        //如果有默认账号且不为空 那么先把默认账号剔除
        if (!empty($defaultAccountInfo)) {
            $defaultAccountInfo->default = 0;
            if (!$defaultAccountInfo->save()) {
                Db::rollBack();
                throw new ApiException('余额扣除失败,修改默认0失败');
            }
        }
        //修改默认账号
        $accountInfo->default = 1;
        if (!$accountInfo->save()) {
            Db::rollBack();
            throw new ApiException('余额扣除失败，修改默认1失败');
        }
    }
    /**
     * 判断今日提现是否已经超过了当日最大提现笔数
     * @return void
     */
    private function checkTodayCount()
    {
        $toDay = date('Y-m-d');
        $count = $this->guildWithdrawalModel->where([['created_at', '>=', $toDay . ' 00:00:00'], ['created_at', '<=', $toDay . ' 23:59:59'], ['user_id', '=', $this->actionUserId]])->whereNotIn('status', [GuildWithdrawal::STATUS_FAIL, GuildWithdrawal::STATUS_YZH_ERR])->count() ?? 0;
        if ($count + 1 > GuildCode::MAXIMUM_WITHDRAWAL_OF_THE_DAY) {
            throw new ApiException('今日已提取超过当日最大提取数量:' . GuildCode::MAXIMUM_WITHDRAWAL_OF_THE_DAY);
        }
    }
    /**
     * 确认余额是否充足
     * @return void
     */
    private function checkAccountBalance()
    {
        $this->balanceInfo = $this->guildBalanceModel->where('user_id', $this->actionUserId)->first();
        if (empty($this->balanceInfo)) {
            throw new ApiException('账户余额不足');
        }
        if ($this->handleRmb > $this->balanceInfo->have_access_balance) {
            throw new ApiException('可提现账户余额不足');
        }
    }
}